import {Promise} from 'es6-promise';
import {Role} from "../core/defines";
import * as utils from '../core/utils';
import {MongoColls} from '../config/mongo';
import {CursorType} from "../core/defines";
import {BaseModel} from "../core/base.model";
import {Collection, ObjectID} from "mongodb";
import {
    FindParam,
    CountParam,
    UpdateParam,
    FindOneParam,
    AggregateParam,
    FindOneUpdateParam,
} from "../core/params";

export enum CartStatus {
    PENDING = 1,
    ORDERED = 2,
    DELETED = 3,
}

export interface UserCart {
    _id?: ObjectID,
    user_id: ObjectID,
    prod_id: ObjectID,
    shop_id: ObjectID,
    num: number,
    status?: CartStatus
    time?: Date,
}

export interface CartFilter {
    _id?: ObjectID,
    user_id?: ObjectID,
    prod_id?: ObjectID,
    page?: number,
    limit?: number,
}

export default class CartModel extends BaseModel {
    name() {
        return 'CartModel';
    }

    constructor(coll: Collection) {
        super(coll);
    }

    checkExist(filter: CartFilter): Promise<any> {
        return this.findOne(new FindOneParam(filter));
    }

    addToCart(filter: CartFilter, card: UserCart): Promise<any> {
        let match = {
            user_id: filter.user_id,
            prod_id: filter.prod_id
        };
        card.status = CartStatus.PENDING;
        card.time = new Date();
        return this.findOneAndUpdate(new FindOneUpdateParam(match, {$set: card}, true));
    };

    deleteCart(filter: CartFilter): Promise<any> {
        let match = {
            _id: filter._id
        };
        let update = {
            $set: {
                status: CartStatus.DELETED
            }
        };
        return this.updateOne(new UpdateParam(match, update));
    };

    getCarts(filter: CartFilter): Promise<any> {
        let {user_id, page, limit} = filter;

        let match = {user_id, status: CartStatus.PENDING};
        let count;
        return this.count(new CountParam(match)).then((totalCount) => {
            count = totalCount;
            let param = new AggregateParam();
            param.push(CursorType.MATCH, match);
            param.push(CursorType.LOOKUP, {
                from: MongoColls.PRODUCT,
                localField: "prod_id",
                foreignField: "_id",
                as: "prod"
            });
            param.push(CursorType.UNWIND, '$prod');
            param.push(CursorType.SORT, {time: -1});
            param.push(CursorType.SKIP, page * limit);
            param.push(CursorType.LIMIT, limit);
            param.push(CursorType.PROJECT, {
                num: 1,
                prod_id: 1,
                thumb: '$prod.base.thumb',
                name: '$prod.base.name',
                price: '$prod.trans.price',
                act_price: '$prod.trans.act_price'
            });
            return this.aggregate(param);
        }).then((records) => {
            return {
                limit,
                curr_page: page,
                total_count: count,
                records: records || [],
                total_page: Math.ceil(count / limit)
            };
        });
    };

    getCartCount(filter: CartFilter): Promise<any> {
        let match = {
            user_id: filter.user_id,
            status: CartStatus.PENDING
        };
        return this.count(new CountParam(match));
    };
}
